package chapter2_nio.obj;

import java.io.*;
import java.net.Socket;

public class NIOSendReceiveUtil_6 {

    //接收一个对象，该对象必须实现Serializable接口
    public static Object recvObject(Socket socket) throws Exception{
        byte[] bytes = recv(socket);
        Object obj =  byteArrayToObjSerializable(bytes);
        return obj;
    }

    //反序列化，将字节转化成对象，Object必须实现Serializable接口
    public static Object byteArrayToObjSerializable(byte[] bytes) throws Exception{
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Object obj = objectInputStream.readObject();
        objectInputStream.close();
        byteArrayInputStream.close();
        return obj;
    }

    //接收包含字节个数的一组字节。
    private static byte[] recv(Socket socket) throws Exception{
        byte[] countBytes = new byte[4];
        readFully(socket, countBytes);
        int count = byteArrayToInt(countBytes);
        byte[] dataBytes = new byte[count];
        readFully(socket, dataBytes);
        return dataBytes;
    }

    //从socket接收字节，把数组bytes填满
    private static void readFully(Socket socket, byte[] bytes) throws Exception{
        InputStream ins = socket.getInputStream();
        int bytesToRead = bytes.length;
        int readCount = 0;
        while (readCount < bytesToRead) {
            int result = ins.read(bytes, readCount, bytesToRead - readCount);
            // Stream意外结束
            if (result == -1) {
                throw new Exception("异常：InputStream意外结束!");
            }
            readCount += result;
        }
    }

    //把字节数组转成对应的整数
    public static int byteArrayToInt(byte[] b) {
        return b[3] & 0xFF |
                (b[2] & 0xFF) << 8 |
                (b[1] & 0xFF) << 16 |
                (b[0] & 0xFF) << 24;
    }






    //recvObject(.)的另一个版本，采用ObjectInputStream
    /*public static Object recvObject0(Socket socket) throws Exception{
        InputStream is = socket.getInputStream();
        ObjectInputStream ois = new ObjectInputStream(is);
        Object obj = ois.readObject();
        return obj;
    }*/




    //发送一个对象，该对象必须实现Serializable接口
    public static void sendObject(Socket socket, Object objSerializable) throws Exception{
        byte[] bytes = objSerializableToByteArray(objSerializable);
        send(socket, bytes);
    }

    //发送包含字节个数的一组字节。
    private static void send(Socket socket, byte[] obytes) throws Exception{
        OutputStream outs = socket.getOutputStream();
        int bytesCount = obytes.length;
        //先发送字节数
        byte[] cntBytes = intToByteArray(bytesCount);
        outs.write(cntBytes, 0, cntBytes.length);
        outs.flush();
        outs.write(obytes, 0, obytes.length);
        outs.flush();
    }

    //把整数转成对应的字节数组
    public static byte[] intToByteArray(int a) {
        return new byte[] {
                (byte) ((a >> 24) & 0xFF),
                (byte) ((a >> 16) & 0xFF),
                (byte) ((a >> 8) & 0xFF),
                (byte) (a & 0xFF)
        };
    }

    //sendObject(.)的另一个版本，采用ObjectOutputStream
    /*public static void sendObject0(Socket socket, Object objSerializable) throws Exception {
        OutputStream os = socket.getOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(os);
        oos.writeObject(objSerializable);
        oos.flush();
    }*/

    //序列化，将对象转化成字节，Object必须实现Serializable接口
    public static byte[] objSerializableToByteArray(Object objSerializable) throws Exception{
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(objSerializable);
        byte[] bytes = byteArrayOutputStream.toByteArray();
        objectOutputStream.close();
        byteArrayOutputStream.close();
        return bytes;
    }


}
